package j.framework.core;

import j.util.Hex;
import j.util.New;
import j.util.StringUtils;
import j.util.ThreeTuple;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 对象（java的根对象）的工具类
 * @author Junhai，Liu
 * 该工具类提供了：
 * <li>判断一个对象数组是否为空</li>
 */
public final class ObjectUtils {
	
	/**
	 * 判断给定的对象数组是否为空
	 * @param array
	 * @return
	 */
	public static boolean isEmpty(Object[] array) {
		return (null == array || array.length == 0);
	}
	
	/**
	 * 计算指定的对象o大内存的大小,以bytes为单位
	 * @param o
	 * @return
	 */
	public static int size(final Object o) {
        if(o==null) {
            return 0;
        }
        try{
        	ByteArrayOutputStream buf = new ByteArrayOutputStream(4096);
        	ObjectOutputStream out = new ObjectOutputStream(buf);
            out.writeObject(o);
            out.flush();
            buf.close();
            return buf.size();
        }catch(IOException e){
        	e.printStackTrace();
        	return 0;
        }
    }
	
	/**
	 * 将指定的java对象（必须实现Serializable接口）转化为字节数组
	 * @param obj
	 * @return
	 */
	public static byte[] toByte(Serializable obj){
		try{
			ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(obj);
			return baos.toByteArray();
		}catch(Exception e){}
		return null;
	}
	
	/**
	 * 将一个java对象序列化成一个字符串，字符串以十六进制表示
	 * @param obj
	 * @return
	 */
	public static String toHex(Serializable obj){
		return Hex.rhex(toByte(obj));
	}
	
	/**
	 * 将用toHex方法序列化的十六进制字符串反序列化为object对象 
	 * @param hex
	 * @return
	 */
	public static Object toObjectFromHex(String hex){
		if(StringUtils.isNullOrEmpty(hex)){
			return null;
		}
		Object obj = null;
		try{
			ByteArrayInputStream bais = new ByteArrayInputStream(Hex.rstr(hex));
			ObjectInputStream ois = new ObjectInputStream(bais);
			obj = ois.readObject();
			return obj;
		}catch(Exception e){}
		return obj;
	}

    /**
     * 将object转换成map，仅检索get|is开头的方法，并将get|is去掉，首字母小写作为key，其值作为value并转换为字符串
     * @param object
     * @return
     */
	public static Map<String,Object> toMap(Object object){
        if(object == null){
            return New.map();
        }
        if(object instanceof Map){
            return (Map<String,Object>)object;
        }
        Map<String, Object> map = New.map();
        Class<?> clazz = object.getClass();
		List<Method> methods = New.list();
		//再获取其父类的方法
		while(clazz!=null && !clazz.equals(Object.class)){
			methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
			clazz = clazz.getSuperclass();
		}
		String key;
		Object objValue;
		try {
			for (Method m : methods) {
				if(m.getParameterTypes().length>0){
					continue;
				}
				key = m.getName();
				if (key.startsWith("is")) {
					key = Character.toLowerCase(key.charAt(2)) + key.substring(3);
				} else if (key.startsWith("get")) {
					key = Character.toLowerCase(key.charAt(3)) + key.substring(4);
				} else {
					continue;
				}
				objValue = m.invoke(object);
				if (null != objValue) {
					map.put(key, objValue);
				}
			}
		}catch (Exception e){
			throw new RuntimeException("在将bean"+object.getClass().getName()+"转换为map时出错，异常："+e.getMessage());
		}
		return map;
    }
    
    /**
     * 比较oldData与newData,以oldData为基础,将不同的增加到List中,TwoTuple中的第一个oldData中的值,第二个newData的值
     * 即:threeTuple.second=修改以前的值;threeTuple.third=修改后的值
     * @param oldData
     * @param newData
     * @return
     */
    public static List<ThreeTuple<String,Object,Object>> compareMapValues(
    		Map<String,Object> oldData,Map<String,Object> newData){
    	List<ThreeTuple<String,Object,Object>> list = New.list();
    	String key;
    	Object v1,v2;//v1为修改前的值,v2为修改后的值
    	for(Map.Entry<String, Object> entry : oldData.entrySet()){
    		key = entry.getKey();
    		if(!newData.containsKey(key)){
    			//第二个map中不存在第一个map中的key,直接跳过去
				continue;
			}
    		v1 = entry.getValue();
    		v2 = newData.get(key);
    		if(null==v1 && null == v2){
				//数据库中与指定的新值都为null，则过
				continue;
			}
			//比较新旧值，若一致，则过滤
			if(null!=v1 && null != v2 && v1.equals(v2)){
				continue;
			}
			if(!newData.containsKey(key)){
				continue;
			}
			list.add(New.tuple(key, v1, v2));
    	}
    	return list;
    }
	/**
	 * 根据bean的属性名称获取其对应的get方法
	 * @param beanClass
	 * @param propertyName
	 * @return
	 */
	public static String generateBeanGetterByPropertyName(Class<?> beanClass,String propertyName){
		String beanGetMethodName = null;
		try {
			Field field = beanClass.getDeclaredField(propertyName);
			if(null!=field){
				//将propertyName的首字母小写
				propertyName = Character.toUpperCase(propertyName.charAt(0))+propertyName.substring(1);
				if(field.getType().equals(boolean.class)){
					beanGetMethodName = "is"+propertyName;
				}else{
					beanGetMethodName = "get"+propertyName;
				}
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return beanGetMethodName;
	}
	/**
	 * 根据bean的属性名称获取其对应的get方法
	 * @param propertyName
	 * @return
	 */
	public static String generateBeanSetterByPropertyName(String propertyName){
		String setterName = null;
		try {
			if(null!=propertyName){
				//将propertyName的首字母小写
				propertyName = Character.toUpperCase(propertyName.charAt(0))+propertyName.substring(1);
				setterName = "set"+propertyName;
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return setterName;
	}
}
